package elf

import (
    "unsafe"
)

// Minimal ELF32 loader skeleton for i386.
// Parses headers, loads PT_LOAD segments into memory, and returns entry point.

const (
    elfMagic     = 0x464C457F // 0x7F 'E' 'L' 'F' little-endian
    elfClass32   = 1
    elfDataLSB   = 1
    elfTypeExec  = 2
    elfMachine386 = 3

    ptLoad = 1
)

type elf32Ehdr struct {
    Ident      [16]byte
    Type       uint16
    Machine    uint16
    Version    uint32
    Entry      uint32
    Phoff      uint32
    Shoff      uint32
    Flags      uint32
    Ehsize     uint16
    Phentsize  uint16
    Phnum      uint16
    Shentsize  uint16
    Shnum      uint16
    Shstrndx   uint16
}

type elf32Phdr struct {
    Type   uint32
    Offset uint32
    Vaddr  uint32
    Paddr  uint32
    Filesz uint32
    Memsz  uint32
    Flags  uint32
    Align  uint32
}

// Load loads an ELF32 image from the provided byte slice into memory.
// Returns the entry point address and true on success.
func Load(image []byte) (uintptr, bool) {
    if len(image) < int(unsafe.Sizeof(elf32Ehdr{})) {
        return 0, false
    }

    // Read ELF header
    eh := (*elf32Ehdr)(unsafe.Pointer(&image[0]))
    magic := *(*uint32)(unsafe.Pointer(&eh.Ident[0]))
    if magic != elfMagic {
        return 0, false
    }
    if eh.Ident[4] != elfClass32 || eh.Ident[5] != elfDataLSB {
        return 0, false
    }
    if eh.Type != elfTypeExec || eh.Machine != elfMachine386 {
        return 0, false
    }

    // Iterate program headers
    phdrBase := int(eh.Phoff)
    phdrSize := int(eh.Phentsize)
    for i := 0; i < int(eh.Phnum); i++ {
        off := phdrBase + i*phdrSize
        if off+int(unsafe.Sizeof(elf32Phdr{})) > len(image) {
            return 0, false
        }
        ph := (*elf32Phdr)(unsafe.Pointer(&image[off]))
        if ph.Type != ptLoad {
            continue
        }
        // Copy segment to target Vaddr
        srcStart := int(ph.Offset)
        srcEnd := srcStart + int(ph.Filesz)
        if srcEnd > len(image) || srcStart < 0 {
            return 0, false
        }
        dst := unsafe.Pointer(uintptr(ph.Vaddr))
        // Copy file bytes
        for j := 0; j < int(ph.Filesz); j++ {
            *(*byte)(unsafe.Pointer(uintptr(dst) + uintptr(j))) = image[srcStart+j]
        }
        // Zero the bss portion (Memsz - Filesz)
        for j := int(ph.Filesz); j < int(ph.Memsz); j++ {
            *(*byte)(unsafe.Pointer(uintptr(dst) + uintptr(j))) = 0
        }
    }

    return uintptr(eh.Entry), true
}